package x.ovo.wechat.bot.core;

import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HtmlUtil;
import lombok.extern.slf4j.Slf4j;
import x.ovo.wechat.bot.common.Constant;
import x.ovo.wechat.bot.common.Context;
import x.ovo.wechat.bot.common.contact.ContactManager;
import x.ovo.wechat.bot.common.entity.Contact;
import x.ovo.wechat.bot.common.entity.Member;
import x.ovo.wechat.bot.common.entity.message.*;
import x.ovo.wechat.bot.common.enums.MessageType;
import x.ovo.wechat.bot.common.http.WechatApi;
import x.ovo.wechat.bot.common.util.WechatUtil;

/**
 * 消息转换器，将api请求返回的{@link Message}转换为具体的{@link Message}
 *
 * @author ovo on 2024/04/23.
 * @since 1.0.0
 */
@Slf4j
public class MessageConvertor {

    private final Context context;
    private final WechatApi api;
    private final ContactManager contactManager;

    public MessageConvertor(Context context) {
        this.context = context;
        this.api = context.getApi();
        this.contactManager = context.getContactManager();
    }

    public Message convert(RawMessage rawMessage) {
        MessageType type = MessageType.get(rawMessage);

        switch (type) {
            case ALL:
                Message chatMessage = new Message();
                this.fillFields(chatMessage, rawMessage, type);
                return chatMessage;
            case TEXT:
                TextMessage textMessage = new TextMessage();
                this.fillFields(textMessage, rawMessage, type);
                textMessage.setAtMe(rawMessage.getContent().contains("@" + this.context.getLoginSession().getNickName()));
                return textMessage;
            case IMAGE:
                ImageMessage imageMessage = new ImageMessage();
                this.fillFields(imageMessage, rawMessage, type);
                imageMessage.setWidth(rawMessage.getImgWidth());
                imageMessage.setHeight(rawMessage.getImgHeight());
                // 获取图片原始数据
                byte[] image = this.api.getImage(rawMessage.getMsgId());
                imageMessage.setBytes(image);
                return imageMessage;
            case VOICE:
                VoiceMessage voiceMessage = new VoiceMessage();
                this.fillFields(voiceMessage, rawMessage, type);
                voiceMessage.setLength(rawMessage.getVoiceLength());
                byte[] voice = this.api.getVoice(rawMessage.getMsgId());
                voiceMessage.setBytes(voice);
                return voiceMessage;
            case VERIFY:
                Message verifyMessage = new Message();
                this.fillFields(verifyMessage, rawMessage, type);
                return verifyMessage;
            case POSSIBLE_FRIEND:
                Message possibleFriendMessage = new Message();
                this.fillFields(possibleFriendMessage, rawMessage, type);
                return possibleFriendMessage;
            case SHARED_REQ:
                Message sharedReqMessage = new Message();
                this.fillFields(sharedReqMessage, rawMessage, type);
                return sharedReqMessage;
            case VIDEO:
                VideoMessage videoMessage = new VideoMessage();
                this.fillFields(videoMessage, rawMessage, type);
                videoMessage.setLength(rawMessage.getPlayLength());
                videoMessage.setBytes(this.api.getVideo(rawMessage.getMsgId()));
                return videoMessage;
            case EMOTICON:
                ImageEmoteMessage emoteMessage = new ImageEmoteMessage();
                emoteMessage.setEmoticonMd5(rawMessage.getContent());
                this.fillFields(emoteMessage, rawMessage, type);
                emoteMessage.setBytes(this.api.getImage(rawMessage.getMsgId()));
                emoteMessage.setWidth(rawMessage.getImgWidth());
                emoteMessage.setHeight(rawMessage.getImgHeight());
                return emoteMessage;
            case POSITION:
            case SHARING:
                SharedMessage sharedMessage = new SharedMessage();
                this.fillFields(sharedMessage, rawMessage, type);
                if (StrUtil.isNotBlank(rawMessage.getOriContent())) {
                    String content = HtmlUtil.unescape(rawMessage.getOriContent());
                    if (content.contains("<title>")) sharedMessage.setTitle(WechatUtil.match("<title>(.*?)</title>", content));
                    if (content.contains("<description>")) sharedMessage.setDescription(WechatUtil.match("<description>(.*?)</description>", content));
                    if (content.contains("<url>")) sharedMessage.setUrl(WechatUtil.match("<url>(.*?)</url>", content));
                }
                return sharedMessage;
            case VOIP:
            case STATUSNOTIFY:
                StatusNotifyMessage statusNotifyMessage = new StatusNotifyMessage();
                this.fillFields(statusNotifyMessage, rawMessage, type);
                return statusNotifyMessage;
            case VOIPNOTIFY:
            case VOIPINVITE:
            case MICROVIDEO:
            case SYSNOTIVET:
            case SYSTEM:
                SystemMessage systemMessage = new SystemMessage();
                this.fillFields(systemMessage, rawMessage, type);
                return systemMessage;
            case RECALLED:
                RevokeMessage revokeMessage = new RevokeMessage();
                this.fillFields(revokeMessage, rawMessage, type);
                return revokeMessage;
            default:
                log.warn("未知消息类型: {}", type);
                Message unknow = new Message();
                this.fillFields(unknow, rawMessage, type);
                return unknow;
        }
    }

    /**
     * 填写字段
     *
     * @param message    聊天消息
     * @param rawMessage 消息
     * @param type       类型
     */
    private void fillFields(Message message, RawMessage rawMessage, MessageType type) {
        message.setId(rawMessage.getMsgId());
        message.setContent(WechatUtil.format(HtmlUtil.unescape(rawMessage.getContent())));
        message.setRaw(rawMessage);
        message.setType(type);

        // 格式化联系人昵称和备注名
        Contact fromUser = this.contactManager.getContactByUserName(rawMessage.getFromUserName());
        fromUser.setNickName(WechatUtil.format(fromUser.getNickName()));
        fromUser.setRemarkName(WechatUtil.format(fromUser.getRemarkName()));
        message.setFromUser(fromUser);
        Contact toUser = this.contactManager.getContactByUserName(rawMessage.getToUserName());
        toUser.setNickName(WechatUtil.format(toUser.getNickName()));
        toUser.setRemarkName(WechatUtil.format(toUser.getRemarkName()));
        message.setToUser(toUser);

        if (rawMessage.isGroup() && rawMessage.getContent().contains(Constant.GROUP_BR) && !StrUtil.equals(this.context.getLoginSession().getUserName(), rawMessage.getFromUserName())) {
            String[] split = rawMessage.getContent().split(Constant.GROUP_BR);
            Member member = this.context.getContactManager().getGroupMember(rawMessage.getFromUserName(), split[0]);
            if (member != null) {
                // 格式化群成员微信昵称和群昵称
                member.setNickName(WechatUtil.format(member.getNickName()));
                member.setDisplayName(WechatUtil.format(member.getDisplayName()));
                message.setMember(member);
                message.setContent(split.length > 1 ? split[1] : "");
            }
        }
    }
}
